package com.example.api.mq.component;

import com.example.entity.domain.member.Member;
import com.example.entity.domain.user.User;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @name: RabbitMqListenter
 * @description: RabbitListener放在类上 @RabbitHandler放在方法上
 * @author: xw.s
 * @date: 2021/5/31-14:14
 */

/**
 * 消息确认是自动的，确认后服务器才会清除该消息
 * 这样有个问题，消息接收到，但是我的业务处理出现了问题，但是消息已经被清除了。
 * 并且java宕机，rabbit也会清除队列，但是实际上queue的autoDelete设置是false
 * 因为channel打开，我们收到了很多消息全都进行了ack，但是实际上给我们只处理了第一个消息就宕机了
 * 综上所述，我们必须手动确认，设置手动确认模式后
 * 消息发送给消费端，消息变成unacked状态，如果宕机消息会重新回到ready状态
 */
@Component
@Slf4j
//@RabbitListener(queues = {"mall-queue"})   //我们使用RabbitMqListenter，此处注释后排出干扰
public class RabbitMqHandler {

    /**
     * 用来接收User类型
     * @param message
     * @param user
     * @param channel
     */
    @RabbitHandler
    public void receiveMessage(Message message, User user, Channel channel) throws IOException {
        log.info("接收到内容开始", String.valueOf(message.getBody()));
        System.out.println(message);
        System.out.println(message.getBody());
        System.out.println(message.getMessageProperties());  //        message.getMessageProperties();//获取消息属性信息
        System.out.println(user);
        System.out.println(channel);
        //do something
        log.info("接收到内容结束");
        /**
         * diliveryTag  这是一个按顺序自增的
         * multiple 是否批量确认，我们用false表示一个一个确认
         */
        long diliveryTag = message.getMessageProperties().getDeliveryTag();
        channel.basicAck(diliveryTag, false); //手动确认完成了哪个消息
        //如果自己不打算处理该业务，还可以拒绝该消息，以便于其他接受者处理
        //下面两个方法都是拒绝
        /**
         * diliveryTag  这是一个按顺序自增的
         * multiple 是否批量
         * requeue  消息是否重新入队  false消息会被丢弃，虽然没有签收，但是rabbit上该消息也没有了。
         */
        channel.basicNack(diliveryTag, false, true);
        /**
         * diliveryTag  这是一个按顺序自增的
         * requeue  消息是否重新入队  false消息会被丢弃
         */
        channel.basicReject(diliveryTag, true);
    }

    /**
     * 用来接收Member类型
     * @param message
     * @param member
     * @param channel
     */
    @RabbitHandler
    public void receiveMessage(Message message, Member member, Channel channel){}
}
